/*
=================================================================================
 Name        : main.c
 Author      : Le Dang Dung
 Version     : 0.1
 Copyright   : ...
 Description :
     Test LCD(PCD8544), KeyPad, Radio driver(RF22) on Target board LPCxpresso LPC1769.
     Incorporated LCP driver libraries: SSP(SPI), UART, timer

// radio module
//                      +-------------------+
//                 ANT 1|      RFM22B       |9  GND
//                     2|                   |10 SDN->GND
//                     3|                   |11 NIRQ
//                     4|            --     |12 NSEL
//                 VCC 5|           |  |    |13 SCK
//                     6|     ----  |  |    |14 SDI
//                     7|    | IC |  --     |15 SDO
//                     8|     ----          |16
//                      +-------------------+
//
// full documentation at Mike McCauley's site: http://www.open.com.au/mikem/arduino/RF22/

   interrupt pin p2.4/j46---------NIRQ  (interrupt request out)
          SS pin p0.6/j8----------NSEL  (chip select in)
         SCK pin p0.7/j7----------SCK   (SPI clock in)
        MOSI pin p0.9/j5----------SDI   (SPI Data in)
        MISO pin p0.8/j6----------SDO   (SPI data out)

=================================================================================
 */
#include "LPC17xx.h"
//#include <cr_section_macros.h>
#include <NXP/crp.h>
#include <stdio.h>
#include <stdlib.h>
#include "timer.h"
#include "pin.h"
#include <ctype.h>
#include <string.h>
#include "uart.h"
#include "type.h"
__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

//#include "ssp.h"
#include "PCD8544.h"
#include "keypad.h"
#include "RF22.h"

#define ROWS  4 //four rows
#define COLS  3 //three columns

/* Define the keymaps */
char alphaKeys[4][3] = {
		{ 'a','d','g' },
		{ 'j','m','p' },
		{ 's','v','y' },
		{ '*',' ','#' }
};

char numberKeys[4][3] = {
		{ '1','2','3' },
		{ '4','5','6' },
		{ '7','8','9' },
		{ '.','0','#' }
};

extern volatile uint32_t UART3Count;
extern volatile uint8_t UART3Buffer[BUFSIZE];
bool _serialOut = false;   // Start with the numeric keypad.
uint8_t buf[RF22_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
char rssiString[3];
uint32_t txCount = 0;
int recvCount = 0;
char txCountString[32];
bool _autoTx = false;
uint8_t hello_msg[32] = "v2.0 hello ";
uint8_t radioParams[] =
{
		RF22_TXPOW_14DBM,

};

/* example of radio receiving method */
void rx()
{
	if (available())
	{
		uint8_t rssi = rssiRead();

		if (recv(buf, &len))
		{
			recvCount++;
			char recvCountString[8]; // one byte, max 255
			itoa(recvCount, recvCountString, 10); // base 10
			LCDclear();
			LCDdrawstring(0,0,recvCountString);
			LCDdrawstring(0,10,(char*)buf);
			memset(rssiString,0,3);
			itoa(rssi, rssiString, 10); // base 10
			LCDdrawstring(0,30,rssiString);
			_serialOut = true;
		}
		else
		{
			LCDdrawstring(0,0,"recv failed");
		}
		LCDdisplay();
	}
}

/* example of radio transmitting method */
void tx(uint8_t* txbuf, uint32_t length)
{
	send(txbuf, length);
	waitPacketSent();
}

/* Take care of keypad events. */
void keypadEvent(KeypadEvent key) {
	static char virtKey = NO_KEY;      // Stores the last virtual key press. (Alpha keys only)
	static char physKey = NO_KEY;      // Stores the last physical key press. (Alpha keys only)
	static uint8_t pressCount;
	static char buildStr[100];
	static uint8_t buildCount;   // here static means variable value retained, eventhough its scope is local

	switch (KeyPadGetState())
	{
	case PRESSED:
		if (key == '#' && virtKey != NO_KEY) // select current char
		{
			buildStr[buildCount] = virtKey;
			buildCount++;
			buildStr[buildCount] = '\0';
			LCDclear();
			LCDdrawstring(0,0,buildStr);
			LCDdisplay();
		}
		else if (key == '*') // del
		{
			if (buildCount > 0)
			{
				buildStr[buildCount-1] = '\0';
				buildCount--;
				LCDclear();
				LCDdrawstring(0,0,buildStr);
				LCDdisplay();
			}
		}
		else
		{              // This is a letter key so we're using the letter keymap.
			if (physKey != key)
			{        // New key so start with the first of 3 characters.
				pressCount = 0;
				virtKey = key;
				physKey = key;
			}
			else
			{                       // Pressed the same key again...
				virtKey++;               // so select the next character on that key.
				pressCount++;            // Tracks how many times we press the same key.
			}
			if(virtKey >= ' ' && virtKey <= '/')
			{
				if (pressCount > 16)
				{        // Last character reached so cycle back to start.
					pressCount = 0;
					virtKey = key;
				}
			}
			else
			{
				if (pressCount > 2)
				{        // Last character reached so cycle back to start.
					pressCount = 0;
					virtKey = key;
				}
			}
			LCDdrawchar(0,40,virtKey);
			LCDdisplay();
		}
		break;
	case IDLE:
		break;

	case HOLD:
		if (key == '#') // send msg...
		{
			if((buildCount-1) != 0)
			{
				LCDdrawstring(10,40,"sending...");
				LCDdisplay();
				buildStr[buildCount-1] = '\0';
				tx((uint8_t*)buildStr,buildCount);
				buildCount = 0;
				LCDclear();
				LCDdrawstring(20,40,"msg sent!");
				if (strcmp(buildStr,"123456") == 0)
				{
					_autoTx = true;
					LCDclear();
					LCDdrawstring(20,40,"auto TX!");
				}
			}
			else
			{
				_autoTx = false;
				LCDclear();
				LCDdrawstring(20,40,"stopped!");
			}
			LCDdisplay();
		}
		else
		{                             // Some key other than '#' was pressed.
			if(key != '*')
			{
				uint8_t row_index = KeyPadCurrentRow();
				uint8_t col_index = KeyPadCurrentCol();
				buildStr[buildCount] = numberKeys[row_index][col_index];
				buildCount++;
				buildStr[buildCount] = '\0';
				LCDclear();
				LCDdrawstring(0,0,buildStr);
				LCDdisplay();
			}
		}
		break;
	case RELEASED:
		if (buildCount >= sizeof(buildStr))  buildCount = 0;    // Our string is full. Start fresh.
		break;
	}  // end switch-case
}  // end keypad events

/* response to serial command */
bool ExecuteSerialCommand(const char* cmd, char * ret)
{
	char response[32] = {};
	char tempString[8];
	uint8_t tmp;
	if (strncmp(cmd,"power up",8) == 0)
	{
		tmp = *radioParams;
		LCDclear();
		if (tmp < 7)
		{
			setTxPower(tmp + 1);
			radioParams[0] = tmp + 1;
			itoa(radioParams[0],tempString,10);
			strncat(response,"TX power up:",12);
			strncat(response,tempString,1);
			strncpy(ret,response,100);
			LCDdrawstring(0,0,response);
		}
		else
		{
			LCDdrawstring(0,0,"TX power max!");
			strncpy(ret,"TX power max!",100);
		}
		LCDdisplay();
		return true;
	}
	else if(strncmp(cmd,"power down",10) == 0)
	{
		tmp = *radioParams;
		LCDclear();
		if (tmp > 0 )
		{
			setTxPower(tmp - 1);
			radioParams[0] = tmp - 1;
			itoa(radioParams[0],tempString,10);
			strncat(response,"TX power down:",14);
			strncat(response,tempString,1);
			strncpy(ret,response,100);
			LCDdrawstring(0,0,response);
		}
		else
		{
			LCDdrawstring(0,0,"TX power min!");
			strncpy(ret,"TX power min!",100);
		}
		LCDdisplay();
		return true;
	}
	else if(strncmp(cmd,"info",4) == 0)
	{
		uint8_t i = 0;
		strncpy(ret,"radio parameters:\n",18);
		for (i ; i < sizeof(radioParams); i++)
		{
			itoa(radioParams[i],tempString,10);
			strncat(ret,tempString,strlen(tempString));
			strncat(ret," ",1);
		}
		return true;
	}
	strncpy(ret,"\0",1);
	return false;
}

/******************************************************************************
 **   Main Function  main()
 ******************************************************************************/
int main (void)
{
	/* SystemClockUpdate() updates the SystemFrequency variable */
	SystemClockUpdate();

	/* LCD init with port resolver */
	LCDInit(12,15,20,13,21,50);
	//setContrast(55);
	LCDcommand(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYALLON);
	_delay_ms(500);
	LCDcommand(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL);
	LCDshowLogo();
	_delay_ms(1000);
	LCDdrawstring(0,0,"MeshPhone 2.0");
	LCDdisplay();
	_delay_ms(1000);
	LCDclear();

	/* UART init */
	const char* welcomeMsg = "Meshphone 2.0:\r\n";
	UARTInit(3, 9600);	/* baud rate setting */
	UARTSend(3, (uint8_t *)welcomeMsg , strlen(welcomeMsg) );

	/*
	 * set up free running timer for our keypad's millis()
	 * clock ticks every 10ms, we can set smaller time interval but that would
	 * produce more interrupts, see timer.c
	 */
	init_timer( 0, TIME_INTERVAL );
	enable_timer( 0 );

	/* Keypad Init */
	uint8_t rowPins[4] = {63, 57, 58, 60}; //connect to the row pinouts of the keypad
	uint8_t colPins[3] = {62, 64, 59}; //connect to the column pinouts of the keypad
	KeyPadInit( makeKeymap(alphaKeys), rowPins, colPins, 4, 3 );
	KeyPadAddEventListener(keypadEvent);

	/* init radio ( chip select - D6/p0.6 ; nIRQ - D56/p2.4 ; 1 == SSP1 */
	if (RF22init(6,56,1) == false)
	{
		LCDdrawstring(0,0,"init failed");
	}
	else if (!setModemConfig(FSK_Rb9_6Fd45))
	{
		LCDdrawstring(0,0,"setConf failed");
	}
	else
	{
		LCDdrawstring(0,0,"radio ok");
	}
	LCDdisplay();
	setTxPower(radioParams[0]);

	_delay_ms(1000);

	uint32_t serialTimeout = 0;
	char cmd[32] = {};
	char res[100] = {};
	uint8_t cmdLen;
	/* Loop forever */
	while(1)
	{
		/* read data from serial buffer when available */
		if ( UART3Count != 0 && serialTimeout < 1000)
		{
			LPC_UART3->IER = IER_THRE | IER_RLS;				/* Disable RBR */
			serialTimeout++;
			cmdLen = UART3Count;
			strncpy(cmd,(char*)UART3Buffer,cmdLen);
			if(cmd[cmdLen-1] == '\n')
			{
				if(ExecuteSerialCommand(cmd,res))
				{
					UARTSend(3, (uint8_t *)res, strlen(res) );
				}
				else
				{
					UARTSend(3, (uint8_t *)cmd, cmdLen );
				}
				UART3Count = 0; // reset buffer counter
				serialTimeout = 0;
			}
			LPC_UART3->IER = IER_THRE | IER_RLS | IER_RBR;		/* Re-enable RBR */
		}
		/* send received data to UART*/
		if(_serialOut == true)
		{
			UARTSend(3, (uint8_t *)buf, len );
			if(len>0)
			{
				UARTSend(3, " rssi ", 6);
				UARTSend(3, (uint8_t *)rssiString, 3);
				UARTSend(3, "\r\n", 2);
			}
			_serialOut = false;
		}
		//delayMs(1,100); // slow polling down a little bit
		/* poll our keypad for action */
		KeyPadGetKey();

		/* check received buffer for data */
		rx();

		if(_autoTx == true)
		{
			txCount++;
			itoa(txCount,txCountString,10);
			strncat(txCountString," v2.0 ping ",12);
			tx((uint8_t*)txCountString,strlen(txCountString));
			_delay_ms(900);
		}
	}
	while ( 1 );
	return 0;
}
/******************************************************************************
 **                            End Of File
 ******************************************************************************/

